package com.symaster.backups.frame.element.pagination;

import com.symaster.backups.frame.element.pagination.util.Util;
import com.symaster.common.swing.util.SwingUtil;


import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import static com.symaster.backups.frame.element.pagination.ButtonType.*;


/**
 * @author yinmiao
 * @version 2024/1/21
 */
public class Pagination extends JComponent implements ActionListener {

    final Color background = new Color(242, 242, 242);
    final Insets buttonMargin = new Insets(0, 0, 0, 0);

    final int buttonNumber;
    final int buttonSize;
    final ChangeRunnable changeRunnable;
    Page page;

    /**
     * 切换页面(public void change(Page page)) 同步对象
     */
    final Object changeTreeLock;
    final Set<ChangeListener> changeListeners;

    public Pagination() {
        this(30, 12);
    }

    public Pagination(int buttonSize, int buttonNumber) {
        this.buttonSize = buttonSize;
        this.buttonNumber = buttonNumber;
        this.changeRunnable = new ChangeRunnable(this);
        this.changeTreeLock = new Object();
        this.changeListeners = new HashSet<>();
        add(getLeftButton());
        add(getRightButton());
        setLayout(new PaginationLayout());
    }

    public void addChangeListener(ChangeListener l) {
        changeListeners.add(l);
    }

    public void removeChangeListener(ChangeListener l) {
        changeListeners.remove(l);
    }

    public void change(Page page) {
        synchronized (changeTreeLock) {
            this.page = page;
        }
        SwingUtilities.invokeLater(changeRunnable);
    }

    @Override
    public void setEnabled(boolean enabled) {
        super.setEnabled(enabled);
        if (page != null) {
            change(page);
        } else {
            for (Component component : getComponents()) {
                component.setEnabled(enabled);
            }
        }
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        Object source = e.getSource();
        if (source instanceof Button && page != null) {
            Button button = (Button) source;
            if (button.getButtonType() == INDEX_BUTTON && button.getPageIndex() != page.getPage()) {
                for (ChangeListener changeListener : changeListeners) {
                    changeListener.pageChange(button.getPageIndex());
                }
            } else if (button.getButtonType() == RIGHT_BUTTON && page.getPage() < page.getTotalPages()) {
                for (ChangeListener changeListener : changeListeners) {
                    changeListener.pageChange(page.getPage() + 1);
                }
            } else if (button.getButtonType() == LEFT_BUTTON && page.getPage() > 1) {
                for (ChangeListener changeListener : changeListeners) {
                    changeListener.pageChange(page.getPage() - 1);
                }
            }
        }
    }

    private Button getRightButton() {
        Button button1 = new Button(RIGHT_BUTTON, 0, SwingUtil.loadIconEnabledCache("right.png", buttonSize, buttonSize));
        button1.setBackground(background);
        button1.addActionListener(this);
        return button1;
    }

    private Button getLeftButton() {
        Button button = new Button(LEFT_BUTTON, 0, SwingUtil.loadIconEnabledCache("left.png", buttonSize, buttonSize));
        button.setBackground(background);
        button.addActionListener(this);
        return button;
    }

    private static class ChangeRunnable implements Runnable {

        private final Pagination pagination;
        private final Button[] buttonFactory;

        public ChangeRunnable(Pagination pagination) {
            this.pagination = pagination;
            this.buttonFactory = new Button[pagination.buttonNumber];
        }

        @Override
        public void run() {
            synchronized (pagination.changeTreeLock) {
                Component[] components = pagination.getComponents();

                Util.getLeftButton(components).setEnabled(pagination.page.getPage() > 1 && pagination.isEnabled());
                Util.getRightButton(components).setEnabled(pagination.page.getPage() < pagination.page.getTotalPages() && pagination.isEnabled());

                List<Component> collect = Arrays.stream(components)
                        .filter(e -> {
                            if (e instanceof Button) {
                                Button button = (Button) e;
                                return button.getButtonType() == INDEX_BUTTON || button.getButtonType() == MORE_BUTTON;
                            }
                            return false;
                        }).collect(Collectors.toList());

                for (Component button : collect) {
                    pagination.remove(button);
                }

                if (pagination.page.getTotalPages() > buttonFactory.length) {

                    /* 第一个按钮 */
                    Button button1 = getButton(0);
                    button1.setPageIndex(1);
                    button1.setText(String.valueOf(1));
                    setButtonEnable(button1);
                    pagination.add(button1);

                    /* 最后一个按钮 */
                    Button button2 = getButton(buttonFactory.length - 1);
                    button2.setPageIndex(pagination.page.getTotalPages());
                    button2.setText(String.valueOf(pagination.page.getTotalPages()));
                    setButtonEnable(button2);
                    pagination.add(button2);

                    for (int i = 2; i < buttonFactory.length - 2; i++) {
                        /* 中间按钮 */
                        Button button3 = getButton(i);
                        button3.setPageIndex(i + 1);
                        button3.setText(String.valueOf(i + 1));
                        setButtonEnable(button3);
                        pagination.add(button3);
                    }

                    /* 第一个按钮 */
                    Button button3 = getButton(1);
                    button3.setPageIndex(2);
                    button3.setText(String.valueOf(2));
                    setButtonEnable(button3);
                    pagination.add(button3);

                    /* 最后一个按钮 */
                    Button button4 = getButton(buttonFactory.length - 2);
                    button4.setButtonType(MORE_BUTTON);
                    button4.setText("...");
                    setButtonEnable(button4);
                    pagination.add(button4);

                    // for (int i = 0; i < buttonFactory.length; i++) {
                    //     Button button = getButton(i);
                    //     button.setPageIndex(i + 1);
                    //
                    //     if (IndexUtil.isFirstOne(i, buttonFactory.length)) {
                    //         button.setText(String.valueOf(1));
                    //     } else if (IndexUtil.isSecondOne(i, buttonFactory.length)) {
                    //
                    //     } else if (IndexUtil.isLastOne(i, buttonFactory.length)) {
                    //         button.setText(String.valueOf(pagination.page.getTotalPages()));
                    //         button.setPageIndex(pagination.page.getTotalPages());
                    //     } else if (IndexUtil.isPenultimate(i, buttonFactory.length)) {
                    //         button.setButtonType(MORE_BUTTON);
                    //         button.setText("...");
                    //     } else {
                    //         button.setText(String.valueOf(i + 1));
                    //     }
                    //
                    //     setButtonEnable(button);
                    //     pagination.add(button);
                    // }
                } else {
                    for (int i = 0; i < pagination.page.getTotalPages(); i++) {
                        int pageIndex = i + 1;

                        Button button = getButton(i);
                        button.setText(String.valueOf(pageIndex));
                        button.setPageIndex(pageIndex);

                        setButtonEnable(button);
                        pagination.add(button);
                    }
                }

                pagination.doLayout();
                pagination.repaint();
            }
        }

        private void setButtonEnable(Button button) {
            if (button.getButtonType() == INDEX_BUTTON) {
                button.setEnabled(button.getPageIndex() != pagination.page.getPage() && pagination.isEnabled());
            } else if (button.getButtonType() == MORE_BUTTON) {
                button.setEnabled(pagination.isEnabled());
            }
        }

        private Button getButton(int i) {
            if (buttonFactory[i] == null) {
                buttonFactory[i] = new Button(INDEX_BUTTON, i, "");
                buttonFactory[i].setMargin(pagination.buttonMargin);
                buttonFactory[i].setBackground(pagination.background);
                buttonFactory[i].addActionListener(pagination);
            }
            return buttonFactory[i];
        }
    }

    public interface ChangeListener {
        void pageChange(int page);
    }
}
